const colors = require('colors');
const path = require('path');
const fs = require('fs');
const { getAllFiles, mkdirsSync } = require('./utils');
const createI18nFile = require('./createI18nFile');
const ReplaceJsContent = require('./replaceScript');
const ReplaceVueTemplate = require('./replaceTemplate');
const {
  autoImportVue2I18n,
  autoImportVue3I18n,
} = require('./automportVueI18n');

let ISVUE3 = false;
let baiduAppid = '';
let baiduKey = '';
let i18nFile;
let config = {
  key: '',
  single: false,
};
let messagesHash = {};
let messages;
let rootPath;
/**
 * 初始化国际化的消息对象
 */
const initMessage = () => {
  if (fs.existsSync(i18nFile)) {
    try {
      messages = require(i18nFile);
      Object.keys(messages).forEach((key) => {
        messagesHash[messages[key]] = key;
      });
    } catch (e) {}
  }
  if (!messages || !Object.keys(messages).length) {
    messages = {};
  }
};
/**
 * 写入国际化消息文件
 */
const writeMessage = () => {
  //若设置了国际化文件目录，则同时更新所有的国际化文件
  if (config.path) {
    try {
      let localeDir = path.join(process.cwd(), config.path ? config.path : '');
      if (!fs.existsSync(localeDir)) {
        mkdirsSync(localeDir);
        console.log(
          `${colors.yellow('➤')} ${colors.yellow(
            `国际化文件路径${config.path}不存在,已设置默认路径 i18n`
          )}`
        );
      }

      fs.readdirSync(localeDir).forEach((file) => {
        file = path.join(localeDir, file);
        if (file !== i18nFile) {
          let oldMessages = require(file);
          fs.writeFileSync(
            file,
            `${JSON.stringify(
              Object.assign({}, messages, oldMessages),
              null,
              '\t'
            )}`,
            'utf8'
          );
        }
      });
    } catch (e) {}
  }
  fs.writeFileSync(i18nFile, `${JSON.stringify(messages, null, '\t')}`, 'utf8');
};

const resetMessageHash = () => {
  //针对没有设置key的情况，恢复每次文件的messageHash
  if (!config.key) {
    messagesHash = {};
  }
};
// 替换注释
const replaceHtmlComment = (content) => {
  //替换注释部分
  let comments = {};
  let commentsIndex = 0;
  const newContent = content.replace(
    /<!--[\s\S]*?-->/gim,
    (match, p1, p2, p3, offset, str) => {
      //排除掉url协议部分
      if (offset > 0 && str[offset - 1] === ':') return match;
      let commentsKey = `<!--comment_${commentsIndex++}-->`;
      comments[commentsKey] = match;
      return commentsKey;
    }
  );
  return { comments, newContent };
};
// 替换注释
const replaceJsComment = (content) => {
  let comments = {};
  let commentsIndex = 0;
  const newContent = content.replace(
    /(\/\*(.|\n|\r)*\*\/)|(\/\/.*)/gim,
    (match, p1, p2, p3, offset, str) => {
      //排除掉url协议部分
      if (offset > 0 && str[offset - 1] === ':') return match;
      let commentsKey = `/*comment_${commentsIndex++}*/`;
      comments[commentsKey] = match;
      return commentsKey;
    }
  );
  return { comments, newContent };
};

/**
 * 替换Vue文件中的需要国际化的部分
 * @param file
 */
const generateVueFile = async (file) => {
  let processFile = path.relative(process.cwd(), file);
  console.log(`➤ ${processFile.blue}`.blue);
  resetMessageHash();
  let hasReplaced = false;
  let content = fs.readFileSync(file, 'utf8');
  const chineseReg = /[\u4e00-\u9fa5]+/gim;
  let _content = content.match(/<template(.|\n|\r)*template>/gim)?.[0];
  if (_content) {
    const { comments, newContent } = replaceHtmlComment(_content);
    if (chineseReg.test(newContent)) {
      _content = new ReplaceVueTemplate({
        content: newContent,
        file,
        messages,
        messagesHash,
        rootPath,
        config,
      }).getContent();
      content = content.replace(/<template(.|\n|\r)*template>/gim, _content);
      //换回注释部分
      content = content.replace(/<!--comment_\d+-->/gim, (match) => {
        return comments[match];
      });
      hasReplaced = true;
    }
  }

  // 替换script中的部分
  _content = content.match(/<script(.|\n|\r)*script>/gim)?.[0];
  if (_content) {
    const { comments, newContent } = replaceJsComment(_content);
    if (chineseReg.test(newContent)) {
      _content = newContent;
      if (ISVUE3) {
        _content = _content.replace(
          /(<script\s*.*>[\n|\r]?)([\s\S]*)(<\/script>)/gim,
          (_, prev, match, after) => {
            match = autoImportVue3I18n(match);
            return `${prev}${match}${after}`;
          }
        );
      }

      _content = new ReplaceJsContent({
        content: _content,
        file,
        messages,
        messagesHash,
        rootPath,
        config,
        suffix: ISVUE3 ? '' : 'this.',
      }).getContent();
      content = content.replace(/<script(.|\n|\r)*script>/gim, _content);
      //换回注释部分
      content = content.replace(/\/\*comment_\d+\*\//gim, (match) => {
        return comments[match];
      });
      hasReplaced = true;
    }
  }

  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  console.log(`✔ ${processFile.green}`.green);
};

const generateJsFile = async (file) => {
  let processFile = path.relative(process.cwd(), file);
  console.log(`➤ ${processFile.blue}`.blue);
  resetMessageHash();
  let hasReplaced = false;
  let content = fs.readFileSync(file, 'utf8');

  let { comments, newContent } = replaceJsComment(content);

  if (ISVUE3) {
    content = autoImportVue3I18n(newContent, true);
  } else {
    content = autoImportVue2I18n(newContent);
  }

  content = new ReplaceJsContent({
    content,
    file,
    messages,
    messagesHash,
    rootPath,
    config,
  }).getContent();

  hasReplaced = true;
  //换回注释部分
  content = content.replace(/\/\*comment_\d+\*\//gim, (match) => {
    return comments[match];
  });
  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  console.log(`✔ ${processFile.green}`.green);
};

/**
 * 入口
 * @param src
 * @param options
 */
module.exports.generate = async (src, options) => {
  try {
    const { version } = require(path.join(process.cwd(), 'node_modules/vue'));
    ISVUE3 = version.startsWith(3);
  } catch (error) {
    console.log(`${colors.red('➤ ERROR')} ${colors.red('没有查找到Vue')}`);
    process.exit(1);
  }

  baiduAppid = options.baiduAppid;
  baiduKey = options.baiduKey;
  config = Object.assign(config, options);
  rootPath = path.join(process.cwd(), src);
  let i18nPath = path.join(process.cwd(), options.path ? options.path : '');
  i18nFile = path.join(i18nPath, `${options.filename}.json`);
  let files = getAllFiles(rootPath);
  initMessage();
  for (const item of files) {
    if (
      item !== i18nFile &&
      (!config.path || (config.path && item.indexOf(i18nPath) < 0))
    ) {
      path.extname(item).toLowerCase() === '.vue'
        ? generateVueFile(item)
        : generateJsFile(item);
    }
  }
  writeMessage();

  if (config.langs.length) {
    for await (let lang of config.langs) {
      lang = lang.split('[')[0].trim();
      await createI18nFile(messages, i18nPath, lang, baiduAppid, baiduKey);
    }
  }
};
